module.exports = function (hljs) {
  var RUBY_METHOD_RE = '[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?'
  var RUBY_KEYWORDS = {
    keyword:
      'and then defined module in return redo if BEGIN retry end for self when ' +
      'next until do begin unless END rescue else break undef not super class case ' +
      'require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor',
    literal:
      'true false nil'
  }
  var YARDOCTAG = {
    className: 'doctag',
    begin: '@[A-Za-z]+'
  }
  var IRB_OBJECT = {
    begin: '#<', end: '>'
  }
  var COMMENT_MODES = [
    hljs.COMMENT(
      '#',
      '$',
      {
        contains: [YARDOCTAG]
      }
    ),
    hljs.COMMENT(
      '^\\=begin',
      '^\\=end',
      {
        contains: [YARDOCTAG],
        relevance: 10
      }
    ),
    hljs.COMMENT('^__END__', '\\n$')
  ]
  var SUBST = {
    className: 'subst',
    begin: '#\\{',
    end: '}',
    keywords: RUBY_KEYWORDS
  }
  var STRING = {
    className: 'string',
    contains: [hljs.BACKSLASH_ESCAPE, SUBST],
    variants: [
      { begin: /'/, end: /'/ },
      { begin: /"/, end: /"/ },
      { begin: /`/, end: /`/ },
      { begin: '%[qQwWx]?\\(', end: '\\)' },
      { begin: '%[qQwWx]?\\[', end: '\\]' },
      { begin: '%[qQwWx]?{', end: '}' },
      { begin: '%[qQwWx]?<', end: '>' },
      { begin: '%[qQwWx]?/', end: '/' },
      { begin: '%[qQwWx]?%', end: '%' },
      { begin: '%[qQwWx]?-', end: '-' },
      { begin: '%[qQwWx]?\\|', end: '\\|' },
      {
        // \B in the beginning suppresses recognition of ?-sequences where ?
        // is the last character of a preceding identifier, as in: `func?4`
        begin: /\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/
      },
      { // heredocs
        begin: /<<[-~]?'?(\w+)(?:.|\n)*?\n\s*\1\b/,
        returnBegin: true,
        contains: [
          { begin: /<<[-~]?'?/ },
          {
            begin: /\w+/,
            endSameAsBegin: true,
            contains: [hljs.BACKSLASH_ESCAPE, SUBST]
          }
        ]
      }
    ]
  }
  var PARAMS = {
    className: 'params',
    begin: '\\(',
    end: '\\)',
    endsParent: true,
    keywords: RUBY_KEYWORDS
  }

  var RUBY_DEFAULT_CONTAINS = [
    STRING,
    IRB_OBJECT,
    {
      className: 'class',
      beginKeywords: 'class module',
      end: '$|;',
      illegal: /=/,
      contains: [
        hljs.inherit(hljs.TITLE_MODE, { begin: '[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?' }),
        {
          begin: '<\\s*',
          contains: [{
            begin: '(' + hljs.IDENT_RE + '::)?' + hljs.IDENT_RE
          }]
        }
      ].concat(COMMENT_MODES)
    },
    {
      className: 'function',
      beginKeywords: 'def',
      end: '$|;',
      contains: [
        hljs.inherit(hljs.TITLE_MODE, { begin: RUBY_METHOD_RE }),
        PARAMS
      ].concat(COMMENT_MODES)
    },
    {
      // swallow namespace qualifiers before symbols
      begin: hljs.IDENT_RE + '::'
    },
    {
      className: 'symbol',
      begin: hljs.UNDERSCORE_IDENT_RE + '(\\!|\\?)?:',
      relevance: 0
    },
    {
      className: 'symbol',
      begin: ':(?!\\s)',
      contains: [STRING, { begin: RUBY_METHOD_RE }],
      relevance: 0
    },
    {
      className: 'number',
      begin: '(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b',
      relevance: 0
    },
    {
      begin: '(\\$\\W)|((\\$|\\@\\@?)(\\w+))' // variables
    },
    {
      className: 'params',
      begin: /\|/,
      end: /\|/,
      keywords: RUBY_KEYWORDS
    },
    { // regexp container
      begin: '(' + hljs.RE_STARTERS_RE + '|unless)\\s*',
      keywords: 'unless',
      contains: [
        IRB_OBJECT,
        {
          className: 'regexp',
          contains: [hljs.BACKSLASH_ESCAPE, SUBST],
          illegal: /\n/,
          variants: [
            { begin: '/', end: '/[a-z]*' },
            { begin: '%r{', end: '}[a-z]*' },
            { begin: '%r\\(', end: '\\)[a-z]*' },
            { begin: '%r!', end: '![a-z]*' },
            { begin: '%r\\[', end: '\\][a-z]*' }
          ]
        }
      ].concat(COMMENT_MODES),
      relevance: 0
    }
  ].concat(COMMENT_MODES)

  SUBST.contains = RUBY_DEFAULT_CONTAINS
  PARAMS.contains = RUBY_DEFAULT_CONTAINS

  var SIMPLE_PROMPT = '[>?]>'
  var DEFAULT_PROMPT = '[\\w#]+\\(\\w+\\):\\d+:\\d+>'
  var RVM_PROMPT = '(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>'

  var IRB_DEFAULT = [
    {
      begin: /^\s*=>/,
      starts: {
        end: '$', contains: RUBY_DEFAULT_CONTAINS
      }
    },
    {
      className: 'meta',
      begin: '^(' + SIMPLE_PROMPT + '|' + DEFAULT_PROMPT + '|' + RVM_PROMPT + ')',
      starts: {
        end: '$', contains: RUBY_DEFAULT_CONTAINS
      }
    }
  ]

  return {
    aliases: ['rb', 'gemspec', 'podspec', 'thor', 'irb'],
    keywords: RUBY_KEYWORDS,
    illegal: /\/\*/,
    contains: COMMENT_MODES.concat(IRB_DEFAULT).concat(RUBY_DEFAULT_CONTAINS)
  }
}
